<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

use App\Models\VideoCategory;
use App\Models\Novel;
use App\Models\Video;
use App\Models\Tag;
use App\Models\OutVideo;
use App\Models\Domain;
use App\Models\CdnDomain;
use App\Models\User;
use App\Models\Order;
use App\Models\PayMethod;
use App\Models\BuyMethod;
use App\Models\AgentPrice;
use App\Models\Notice;
use App\Models\ShortUrl;

use App\Services\PayService;
use App\Services\CdnService;
use App\Services\AgentPriceService;
use App\Models\BadOpenid;

use App\Jobs\RecordVisit;
use App\Jobs\CreateUser;
use App\Jobs\CreateOrder;

use EasyWeChat\Factory;

class IndexController extends Controller
{
    /**
     * 客户端入口函数
     *
     * @param Request $request
     * @return void
     */
    public function index(Request $request){
        if(!$request->has('code')){
            return errorGo('error_enter');
        }
        $from_code = $request->code;
        $code_data = decodeCode($from_code);
        if(count($code_data)<=3){
            return errorGo('error_code');
        }
        $openid = $request->uopenid??'-';
        $agent_id = $code_data[1];
        
        $ip = getIp();
        $ua = $_SERVER['HTTP_USER_AGENT'];
        
        //------------ 创建用户 队列 ------------
        if($openid!='-'){
            $data=[
                'agent_id'=>$agent_id,
                'code'=>$from_code??'',
                'url'=>$request->fullUrl(),
                'ua'=>$ua,
                'last_ip'=>$ip,
                'openid'=>$openid,
            ];
            CreateUser::dispatch($data);
        }
        //------------ 创建用户 结束 ------------
         //获取落地
         $born_domain = Cache::rememberForever('born_domain',  function () {
            //落地有可能没有了，所以加锁防止没有时缓存穿透
            return Cache::lock('born_domain')->get(function () {
                // 获取无限期锁并自动释放...
                return Domain::show()->born()->orderBy('sort')->value('domain');
            });
        });
        //缓存为空
        if(!$born_domain){
            //清空缓存
            Cache::forget('born_domain');
            // 没有落地域名了，跳转
            return errorGo('noborn');
        }
        // pc 访问
        if(strpos($ua,'Windows NT') !== false){ 
            return errorGo('from_pc');
        }
        //openid 绑定设备，定时任务清理
        $link_ua = cache()->rememberForever("openid_ua:{$openid}",function()use($ua){
            return md5(filterUa($ua));
        } );
        if($link_ua !=  md5(filterUa($ua))){
            //------------ 统计访问 队列 ------------
            $view_params=[
                'code'=>$from_code??'',
                'path'=>$request->path(),
                'url'=>$request->fullUrl(),
                'ua'=>$ua,
                'ip'=>$ip,
                'openid'=>$openid,
                'tips'=>'疑似腾讯检测机器人已拦截',
                'category'=>1, //1入口，2落地，3播放，4支付，5支付成功
            ];
            RecordVisit::dispatch($view_params);
            //------------ 统计访问 结束 ------------
            return errorGo('error_user');
        }
        //------------ 统计访问 队列 ------------
        $view_params=[
            'code'=>$from_code??'',
            'path'=>$request->path(),
            'url'=>$request->fullUrl(),
            'ua'=>$ua,
            'ip'=>$ip,
            'openid'=>$openid,
            'category'=>1, //1入口，2落地，3播放，4支付，5支付成功
        ];
        RecordVisit::dispatch($view_params);
        //------------ 统计访问 结束 ------------
        $code = createCode($agent_id,$openid);
        //缓存盒子外链
        Cache::remember('out_video:'.$code, 3600,function () use($from_code){
            $short_url =  ShortUrl::where('key',$from_code)->first();
            if($short_url){
                return $short_url->out_video;
            }
            return null;
        });
        
        unset($from_code);
        unset($ip);
        unset($ua);
        unset($agent_id);
        return redirect('http://'.$born_domain."/born?code={$code}");
    }

    /**
     * 落地主页
     *
     * @param Request $request
     * @return void
     */
    public function born(Request $request){
        $from_code = $request->code;
        //解析code
        $code_data = decodeCode($from_code);
        //重新编码
        $code = createCode($code_data[1],$code_data[2]);
        //------------ 统计访问 队列 ------------
        $view_params=[
            'code'=>$from_code??'',
            'path'=>$request->path(),
            'url'=>$request->fullUrl(),
            'ip'=>getIp(),
            'openid'=>$code_data[2],
            'ua'=>$_SERVER['HTTP_USER_AGENT'],
            'category'=>2, //1入口，2落地，3播放，4支付，5支付成功
        ];
        RecordVisit::dispatch($view_params);
        //------------ 统计访问 结束 ------------
        
        //视频分类
        $categories = Cache::rememberForever('categories',  function () {
            return VideoCategory::show()->orderBy('sort')->get()->makeHidden('name')->toArray();
        });
        //图片加载方式
        $pic_type = config('visit.pic_type');//db_base64 数据库base64, encode_img 图片加密走cdn，line 图片服务器直连
        $videos=[];
        $img_cdns =[];
        $img_domain = '';
        if($pic_type == 'encode_img'){//图片加密方式
            cache()->forget('loaded_videos:'.$code_data[2]);
            // 获取初始视频列表()
            $videos = cache()->remember('init_videos_file', 300,function ()use($code_data){
                $video_builder = Video::show()->inRandomOrder()->limit(14)->with('category');//where('is_recommend',1)->
                $videos = $video_builder->get()->makeHidden(['base64','title','category_id','state','is_recommend']);
                $ids = [];
                $videoarray = [];
                foreach($videos as $item){
                    $ids[] = $item->id;
                    $item->_category = $item->category->c_name;
                    unset($item->category);
                    $videoarray[] = $item->toarray();
                }
                if(count($ids)){
                    cache()->put('loaded_videos:'.$code_data[2], array_filter($ids),600);
                }
                return $videoarray;
            });
            //图片cdn
           $img_cdns = (new CdnService())->getImgCdn();
           if($img_cdns['state']!='success' || ($img_cdns['img_cdn1']=='' && $img_cdns['img_cdn2']=='')){
               return errorGo($img_cdns['state']);
           }
        }
        else if($pic_type == 'db_base64'){//数据库直接返回base64图片
            cache()->forget('loaded_videos:'.$code_data[2]);
            // 获取初始视频列表()
            $videos = cache()->remember('init_videos_db', 300,function ()use($code_data){
                $video_builder = Video::show()->inRandomOrder()->limit(14)->with('category');//where('is_recommend',1)->
                $videos = $video_builder->get()->makeHidden(['title','category_id','state','is_recommend']);
                $ids = [];
                $videoarray = [];
                foreach($videos as $item){
                    $ids[] = $item->id;
                    $item->_category = $item->category->c_name;
                    unset($item->category);
                    $videoarray[] = $item->toarray();
                }
                if(count($ids)){
                    cache()->put('loaded_videos:'.$code_data[2], array_filter($ids),600);
                }
                return $videoarray;
            });
        }
        else{//图片服务器直连
            cache()->forget('loaded_videos:'.$code_data[2]);
            //图片服务器域名
            $img_domain = cache()->rememberForever('img_domain',  function () {
                //加锁防止没有时缓存穿透
                return Cache::lock('img_domain')->get(function () {
                    // 获取无限期锁并自动释放...
                    return CdnDomain::show()->where('type',3)->value('domain');
                });
            });
            // 获取初始视频列表()
            $videos = cache()->remember('init_videos_file', 300,function ()use($code_data){
                $video_builder = Video::show()->inRandomOrder()->limit(14)->with('category');//where('is_recommend',1)->
                $videos = $video_builder->get()->makeHidden(['base64','title','category_id','state','is_recommend']);
                $ids = [];
                $videoarray = [];
                foreach($videos as $item){
                    $ids[] = $item->id;
                    $item->_category = $item->category->c_name;
                    unset($item->category);
                    $videoarray[] = $item->toarray();
                }
                if(count($ids)){
                    cache()->put('loaded_videos:'.$code_data[2], array_filter($ids),600);
                }
                return $videoarray;
            });
        }
        
        //打乱顺序
        shuffle($videos);
        //保存该用户已经加载的视频id到缓存，防止后面触底加载重复
        if(!(cache()->has('loaded_videos:'.$code_data[2]))){
            $loaded_video_ids = [];
            foreach($videos as $item){
                $loaded_video_ids[] = $item['id'];
            }
            cache()->put('loaded_videos:'.$code_data[2], array_filter($loaded_video_ids),600);
        }
       
        //公告
        $notices = Cache::rememberForever('user_notices',  function () {
            //落地有可能没有了，所以加锁防止没有时缓存穿透
            return Cache::lock('user_notices')->get(function () {
                // 获取无限期锁并自动释放...
                $notices = Notice::show()->user()->select('id','title','content')->orderBy('updated_at','desc')->get()->toArray();
                if(count($notices)){
                    return $notices;
                }else return [];
            });
        });
        if(count($notices)<=0){
            Cache::forget('user_notices');
        }
        //代理价格
        $key = 'video_price:agent_';
        $key.= $code_data[1];
        $price = Cache::remember($key, 7200,function ()use($code_data) {
            $agent_price_setting = AgentPriceService::getAgentPrice($code_data[1]);
            $price = 1;
            if($agent_price_setting['min_price'] == $agent_price_setting['max_price'] && $agent_price_setting['min_price']>0){
                $price = $agent_price_setting['min_price'];
            }
            else{
                $price = rand($agent_price_setting['min_price'], $agent_price_setting['max_price']);
            }
            $once_price = $price??1.00;
            return $once_price;
        });
        //视频播放域名
        $video_domain = '';
        if(config('visit.preview_video')){
            $cdn_service = new CdnService();
            $video_cdns = $cdn_service->getVideoCdn();
            if($video_cdns['state']!='success' || ($video_cdns['video_cdn1']=='' && $video_cdns['video_cdn2']=='')){
                return errorGo($video_cdns['state']);
            }
            $video_domain = $video_cdns['video_cdn1']['domain'];
        }
        //盒子链接
        $out_video = cache()->get('out_video:'.$from_code);
        //返回视图
        return view('mobile.index',compact(['code','categories','videos','video_domain','img_cdns','notices','price','out_video','pic_type','img_domain'])); 
    }


    /**
     * 支付
     *
     * @param Request $request
     * @return void
     */
    public function pay(Request $request){
        //视频ID
        $video_id = $request->video_id;
        if(!$video_id){
            return errorGo('errorvideo');
        }
        //视频是否存在
        $video = Video::find($video_id)->makeHidden(['base64','title','category_id','state','is_recommend']);
        if(!boolval($video)){
            return errorGo('novideo');
        }
        //校验身份
        $code = $request->code;
        //解析code
        $code_data = decodeCode($code);
        $openid = $code_data[2];
        $ip = getIp();
        //重新编码
        $code = createCode($code_data[1],$code_data[2]);
        //单价
        $key = 'video_price:agent_';
        $key.= $code_data[1];
        $price = Cache::remember($key, 7200,function ()use($code_data) {
            $agent_price_setting = AgentPriceService::getAgentPrice($code_data[1]);
            $price = 1;
            if($agent_price_setting['min_price'] == $agent_price_setting['max_price'] && $agent_price_setting['min_price']>0){
                $price = $agent_price_setting['min_price'];
            }
            else{
                $price = rand($agent_price_setting['min_price'], $agent_price_setting['max_price']);
            }
            $once_price = $price??1;
            return $once_price;
        });
        //判断用户是否已购买
        $ifpay = Cache::get("paid:{$openid}:{$video_id}", 0);
        $db_exists = Order::paid()->where(['openid'=>$openid,'video_id'=>$video_id])->where('paid_at','>=',Carbon::now()->addDays(-1))->exists();
        $paid =  $ifpay||$db_exists;
        //已支付，跳转播放
        if($paid){
            //视频cdn
            $cdn_service = new CdnService();
            $video_cdns = $cdn_service->getVideoCdn();
            if($video_cdns['state']!='success' || ($video_cdns['video_cdn1']=='' && $video_cdns['video_cdn2']=='')){
                return errorGo($video_cdns['state']);
            }
            return response()->view('mobile.play',compact(['price','code','video_cdns','video']));  
            // return response()->view('mobile.play',compact(['price','code','video_cdns','video']))->header('timeStamp', time());  
        }
        
        //------------ 统计访问 队列 ------------
        $view_params=[
            'code'=>$code??'',
            'path'=>$request->path(),
            'url'=>$request->fullUrl(),
            'ip'=>$ip,
            'ua'=>$_SERVER['HTTP_USER_AGENT']??'',
            'openid'=>$openid,
            'category'=>4, //1入口，2落地，3播放，4支付，5支付成功
        ];
        RecordVisit::dispatch($view_params);
        //------------ 统计访问 结束 ------------
        //获取支付方式
        $pay_method =[];
        //是否封禁的openid
        $bad_openid = cache()->remember("bad_openid:{$openid }",Carbon::now()->addDays(1),function()use($openid ){
            $exists = BadOpenid::where(['openid'=>$openid])->exists();
            return $exists;
        } );
        if($bad_openid){
            //投诉用户走扫码通道
            $pay_method = (new PayService())->getSmPayMethod();
            if(empty($pay_method['type'] )){
                cache()->forget('pay_method_sm');
                return back();
            }
        }else{
            //获取支付方式
            $pay_method = (new PayService())->getPayMethod();
        }
        if(empty($pay_method['type'] ) || count($pay_method['config'])<=0){
            return back();
        }
        
        /**
         * 支付方式
         */
        //微信商户内付
        if($pay_method['type']=='wechat_official'){
            $redirect = urlencode("http://{$pay_method['config']['domain']}/payborn?base_code={$code}&video_id={$video_id}");
            $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$pay_method['config']['appid']}&redirect_uri={$redirect}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
            return  redirect($url);
        }
        ////////////////////////// 非内付方式 ////////////////////////////////////////////////////
        //订单号
        $no = createOrderNo().str_pad($video_id, 5, '0', STR_PAD_LEFT);
        // 订单信息
        $order =[
            'agent_id'=>$code_data[1],
            'openid'=>$code_data[2],
            'video_id'=>$video_id,
            'code' =>$code,
            'no'=>$no,
            'price'=>$price,
            'agent_price'=>$price,
            'appid'=>$pay_method['config']['appid']??'',
            'mch_id'=>$pay_method['config']['mchid'],
            'type'=>$pay_method['type']??'',
            'ip'=>$ip,
            'ua'=>$_SERVER['HTTP_USER_AGENT']??''
        ];
        // 队列执行创建订单
        CreateOrder::dispatch($order);
        // 订单队列结束

        //支付方式跳转
        switch($pay_method['type']){
            case 'miniprogram': //小程序通道
                //获取落地
                $born_domain = cache()->rememberForever('born_domain',  function () {
                    //落地有可能没有了，所以加锁防止没有时缓存穿透
                    return cache()->lock('born_domain')->get(function () {
                        // 获取无限期锁并自动释放...
                        return Domain::show()->born()->orderBy('sort')->value('domain');
                    });
                });
                
                $config = [
                    'app_id' => $pay_method['config']['appid'],
                    'secret' => $pay_method['config']['appsecret'],
                    // 下面为可选项
                    // 指定 API 调用返回结果的类型：array(default)/collection/object/raw/自定义类名
                    'response_type' => 'array',
                    'log' => [
                        'level' => 'debug',
                        'file' =>'./logs/miniprogram.log',
                    ],
                ];
                
                $app = Factory::miniProgram($config);
                $response = $app->app_code->getQrCode("pages/order/temppay?no={$no}&price={$price}&domian={$born_domain}");
                // $response 成功时为 EasyWeChat\Kernel\Http\StreamResponse 实例，失败为数组或你指定的 API 返回类型
                
                // 保存小程序码到文件
                if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
                    $filename = $response->saveAs(storage_path('app/public/images/temp'),random(9).".png");
                    $qrcode = 'storage//images/temp/'.$filename;
                    $expire=180;
                    $checkUrl = '';
                    return view('mobile.pay.miniprogram.qrcode',compact('no','qrcode','price','expire','code','checkUrl','video_id','born_domain'));
                    
                }else{
                    return back();
                }
                break;
            case 'HS': //和珅通道
                $service = new PayService();
                $res = $service->hsCreateOrder($pay_method['config'],$price,$order['no']);
                return redirect($res);
            case 'sevenSm': //七七扫码通道
                //获取落地
                $born_domain = cache()->rememberForever('born_domain',  function () {
                    //落地有可能没有了，所以加锁防止没有时缓存穿透
                    return cache()->lock('born_domain')->get(function () {
                        // 获取无限期锁并自动释放...
                        return Domain::show()->born()->orderBy('sort')->value('domain');
                    });
                });
                $service = new PayService();
                $result = $service->smCreateOrder($pay_method['config'],$price,$no,$born_domain);

                if($result['code']!=0){
                    \Log::error($result);
                    return back();
                }else{
                    $res['status'] = 1;
                    $res['config'] = $result ['result'];
                    $res['type'] = '7sm';
                    $html = "<form id='form' name='form' action='/pay/7-qrcode' method='post'>";
                    foreach ($res['config'] as $key => $val) {
                        $html.= "<input type='hidden' name='".$key."' value='".$val."'/>";
                    }
                    $html.= "</form>";
                    $html.= "<script>document.forms['form'].submit();</script>";
                    echo $html;
                }
                break;
            default:
                cache()->forget('pay_method');
                return back();
                break;
        }
    }


    /**
     * 内付支付落地页
     *
     * @param Request $request
     * @return void
     */
    public function payBorn(Request $request){
        $pay_method = (new PayService())->getWechatPayMethod();
        $http = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$pay_method['config']['appid']}&secret={$pay_method['config']['appsecret']}&code={$request->code}&grant_type=authorization_code";
        $res = file_get_contents($http);
        $result = json_decode($res,true);
        $pay_openid = $result['openid']??'-';
        
        //视频ID
        $video_id = $request->video_id;
        $video = Video::show()->where('id',$video_id)->first()->makeHidden(['base64','title','category_id','state','is_recommend']);
        if($video){
            $video = $video->toArray();
        }else{
            return back();
        }
        //解析code
        $code = $request->base_code;
        $code_data = decodeCode($code);
        //重新编码
        $code = createCode($code_data[1],$code_data[2]);

        //获取该代理单片价格
        $key = 'video_price:agent_';
        $key.= $code_data[1];
        $once_price = Cache::remember($key, 7200,function ()use($code_data) {
            $agent_price_setting = AgentPriceService::getAgentPrice($code_data[1]);
            $price = 1;
            if($agent_price_setting['min_price'] == $agent_price_setting['max_price'] && $agent_price_setting['min_price']>0){
                $price = $agent_price_setting['min_price'];
            }
            else{
                $price = rand($agent_price_setting['min_price'], $agent_price_setting['max_price']);
            }
            $once_price = $price??1;
            return $once_price;
        });
        return response()->view('mobile.needpay',compact(['code','once_price','video','pay_openid']));  
    }

    /***
     * 播放
     */
    public function play(Request $request){

        $video_id = $request->video_id;
        if(!$video_id){
            return errorGo('errorvideo');
        }
        $video = Video::with('tags')->find($video_id)->makeHidden(['base64','title','category_id','state','is_recommend']);
        if(!boolval($video)){
            return errorGo('novideo');
        }
        //校验身份
        $code = $request->code;
        //解析code
        $code_data = decodeCode($code);
        $openid = $code_data[2];
        $ip = getIp();
        //重新编码
        $code = createCode($code_data[1],$code_data[2]);
        $ua = $_SERVER['HTTP_USER_AGENT'];
        //判断用户是否已购买
        $ifpay = Cache::get("paid:{$openid}:{$video_id}", 0);
        $db_exists = Order::paid()->where(['openid'=>$openid,'video_id'=>$video_id])->where('paid_at','>=',Carbon::now()->addDays(-1))->exists();
        $paid = $ifpay||$db_exists;
        //未支付，跳转支付
        if(!$paid){
            return redirect("/pay?code={$code}&video_id={$video_id}");
        }

        //------------ 统计访问 队列 ------------
        $view_params=[
            'code'=>$request->code??'',
            'path'=>$request->path(),
            'url'=>$request->fullUrl(),
            'ip'=>$ip,
            'ua'=>$ua,
            'openid'=>$openid,
            'category'=>3, //1入口，2落地，3播放，4支付，5支付成功
        ];
        RecordVisit::dispatch($view_params);
        //------------ 统计访问 结束 ------------
        $cdn_service = new CdnService();
        $video_cdns = $cdn_service->getVideoCdn();
        if($video_cdns['state']!='success' || ($video_cdns['video_cdn1']=='' && $video_cdns['video_cdn2']=='')){
            return errorGo($video_cdns['state']);
        }
        //获取该代理单片价格
        $key = 'video_price:agent_';
        $key.= $code_data[1];
        $price = Cache::remember($key, 7200,function ()use($code_data) {
            $agent_price_setting = AgentPriceService::getAgentPrice($code_data[1]);
            $price = 1;
            if($agent_price_setting['min_price'] == $agent_price_setting['max_price'] && $agent_price_setting['min_price']>0){
                $price = $agent_price_setting['min_price'];
            }
            else{
                $price = rand($agent_price_setting['min_price'], $agent_price_setting['max_price']);
            }
            $once_price = $price??1;
            return $once_price;
        });
        //图片加载方式
        $pic_type = config('visit.pic_type');//db_base64 数据库base64, encode_img 图片加密文件走cdn
        //返回视图
        return response()->view('mobile.play',compact(['code','video_cdns','video','price','pic_type']));  
    }

    /**
     * 视频标签页面
     */
    public function tagView(Request $request){
         //校验身份
         $code = $request->code;
         //解析code
         $code_data = decodeCode($code);
         //重新编码
         $code = createCode($code_data[1],$code_data[2]);
        //视频标签
        $tags = Cache::rememberForever('tags',  function () {
            return Tag::show()->select('id','name')->get()->toArray();
        });
        //获取该代理单片价格
        $key = 'video_price:agent_';
        $key.= $code_data[1];
        $price = Cache::remember($key, 7200,function ()use($code_data) {
            $agent_price_setting = AgentPriceService::getAgentPrice($code_data[1]);
            $price = 1;
            if($agent_price_setting['min_price'] == $agent_price_setting['max_price'] && $agent_price_setting['min_price']>0){
                $price = $agent_price_setting['min_price'];
            }
            else{
                $price = rand($agent_price_setting['min_price'], $agent_price_setting['max_price']);
            }
            $once_price = $price??1;
            return $once_price;
        });
        //视频播放域名
        $video_domain = '';
        if(config('visit.preview_video')){
            $cdn_service = new CdnService();
            $video_cdns = $cdn_service->getVideoCdn();
            if($video_cdns['state']!='success' || ($video_cdns['video_cdn1']=='' && $video_cdns['video_cdn2']=='')){
                return errorGo($video_cdns['state']);
            }
            $video_domain = $video_cdns['video_cdn1']['domain'];
        }
        //图片加载方式
        $pic_type = config('visit.pic_type');//db_base64 数据库base64, encode_img 图片加密文件走cdn
        //返回视图
        return response()->view('mobile.tag',compact(['code','tags','pic_type','price','video_domain']));  
    }


    /**
     * 负载检测
     */
    public function online(Request $request){
        return 'I am fine !';
    }
}
